package com.shrct.businessprocess.budget.impl;

import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import com.shrct.businessprocess.budget.RCBudget;
import com.shrct.businessprocess.budget.RCBudgetCategory;
import com.shrct.businessprocess.budget.RCC3Budget;
import com.shrct.businessprocess.budget.RCC3BudgetType;
import com.shrct.businessprocess.budget.RCCostBreakDown;
import com.shrct.businessprocess.budget.impl.RCBudgetImpl;
import com.shrct.businessprocess.budget.proxy.RCCostBreakDownProxy;
import com.shrct.businessprocess.common.CurrencyType;
import com.shrct.businessprocess.diagnose.IDiagnoseAcceptor;
import com.shrct.businessprocess.project.RCExchangeRate;
import com.shrct.businessprocess.project.RCProject;
import com.shrct.businessprocess.project.RCProjectMoney;
import com.shrct.businessprocess.project.impl.RCProjectImpl;
import edu.fudan.mylang.common.NumberExtensions;
import edu.fudan.mylang.common.ObjectExtensions2;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IObjectFactory;
import java.util.Collection;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.DoubleExtensions;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.Functions.Function2;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;

@Entity
@DiscriminatorValue("RCCOSTBREAKDOWN_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "rccostbreakdown")
public class RCCostBreakDownImpl extends BaseModelObject implements RCCostBreakDown {
  public RCCostBreakDownImpl() {
    super();
  }
  
  @JoinColumn(name = "project_id")
  @ManyToOne(targetEntity = RCProjectImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private RCProject project;
  
  public RCProject getProject() {
    return this.project;
  }
  
  public RCCostBreakDown setProject(final RCProject project) {
    this.project = project;
    return this;			
    
  }
  
  @OneToMany(targetEntity = RCBudgetImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, mappedBy = "cbd")
  private Collection<RCBudget> budgets = new java.util.ArrayList<com.shrct.businessprocess.budget.RCBudget>();;
  
  public Collection<RCBudget> getBudgets() {
    return this.budgets;
  }
  
  public RCCostBreakDown removeAllBudgets() {
    for(RCBudget obj : this.budgets){
    	getObjectFactory().delete(obj);
    }
    this.budgets.clear();
    return this;	
    
  }
  
  public RCCostBreakDown removeFromBudgets(final RCBudget rCBudget) {
    this.budgets.remove(rCBudget);
    getObjectFactory().delete(rCBudget);
    return this;
    
  }
  
  public Double getRemainAmount(final RCBudgetCategory part) {
    double _xblockexpression = (double) 0;
    {
      final Function1<RCBudget,Boolean> _function = new Function1<RCBudget,Boolean>() {
          public Boolean apply(final RCBudget it) {
            RCBudgetCategory _category = it.getCategory();
            boolean _equals = Objects.equal(_category, part);
            return Boolean.valueOf(_equals);
          }
        };
      Iterable<RCBudget> _filter = IterableExtensions.<RCBudget>filter(this.budgets, _function);
      final Function1<RCBudget,Double> _function_1 = new Function1<RCBudget,Double>() {
          public Double apply(final RCBudget it) {
            Double _remainAmount = it.getRemainAmount();
            return _remainAmount;
          }
        };
      Iterable<Double> _map = IterableExtensions.<RCBudget, Double>map(_filter, _function_1);
      final Function2<Double,Double,Double> _function_2 = new Function2<Double,Double,Double>() {
          public Double apply(final Double d1, final Double d2) {
            double _plus = DoubleExtensions.operator_plus(d1, d2);
            return Double.valueOf(_plus);
          }
        };
      Double _reduce = IterableExtensions.<Double>reduce(_map, _function_2);
      final Double result = NumberExtensions.nullsafe(_reduce);
      double _xifexpression = (double) 0;
      boolean _lessThan = ((result).doubleValue() < 0);
      if (_lessThan) {
        _xifexpression = 0d;
      } else {
        _xifexpression = result;
      }
      _xblockexpression = (_xifexpression);
    }
    return Double.valueOf(_xblockexpression);
  }
  
  public RCProjectMoney getContractPrice() {
    final Function1<RCBudget,RCProjectMoney> _function = new Function1<RCBudget,RCProjectMoney>() {
        public RCProjectMoney apply(final RCBudget it) {
          RCProjectMoney _contractPrice = it.getContractPrice();
          return _contractPrice;
        }
      };
    Iterable<RCProjectMoney> _map = IterableExtensions.<RCBudget, RCProjectMoney>map(this.budgets, _function);
    final Function2<RCProjectMoney,RCProjectMoney,RCProjectMoney> _function_1 = new Function2<RCProjectMoney,RCProjectMoney,RCProjectMoney>() {
        public RCProjectMoney apply(final RCProjectMoney m1, final RCProjectMoney m2) {
          RCProjectMoney _plus = m1.plus(m2);
          return _plus;
        }
      };
    RCProjectMoney _reduce = IterableExtensions.<RCProjectMoney>reduce(_map, _function_1);
    final Function1<Void,RCProjectMoney> _function_2 = new Function1<Void,RCProjectMoney>() {
        public RCProjectMoney apply(final Void it) {
          RCProjectMoney _zeroAmount = RCCostBreakDownImpl.this.getZeroAmount();
          return _zeroAmount;
        }
      };
    RCProjectMoney _withDefault = ObjectExtensions2.<RCProjectMoney>withDefault(_reduce, _function_2);
    RCExchangeRate _exchangeRate = this.getExchangeRate();
    RCProjectMoney _money = _withDefault.toMoney(_exchangeRate);
    return _money;
  }
  
  public RCProjectMoney getNetPrice() {
    final Function1<RCBudget,RCProjectMoney> _function = new Function1<RCBudget,RCProjectMoney>() {
        public RCProjectMoney apply(final RCBudget it) {
          RCProjectMoney _netPrice = it.getNetPrice();
          return _netPrice;
        }
      };
    Iterable<RCProjectMoney> _map = IterableExtensions.<RCBudget, RCProjectMoney>map(this.budgets, _function);
    final Function2<RCProjectMoney,RCProjectMoney,RCProjectMoney> _function_1 = new Function2<RCProjectMoney,RCProjectMoney,RCProjectMoney>() {
        public RCProjectMoney apply(final RCProjectMoney m1, final RCProjectMoney m2) {
          RCProjectMoney _plus = m1.plus(m2);
          return _plus;
        }
      };
    RCProjectMoney _reduce = IterableExtensions.<RCProjectMoney>reduce(_map, _function_1);
    final Function1<Void,RCProjectMoney> _function_2 = new Function1<Void,RCProjectMoney>() {
        public RCProjectMoney apply(final Void it) {
          RCProjectMoney _zeroAmount = RCCostBreakDownImpl.this.getZeroAmount();
          return _zeroAmount;
        }
      };
    RCProjectMoney _withDefault = ObjectExtensions2.<RCProjectMoney>withDefault(_reduce, _function_2);
    RCExchangeRate _exchangeRate = this.getExchangeRate();
    RCProjectMoney _money = _withDefault.toMoney(_exchangeRate);
    return _money;
  }
  
  public RCProjectMoney getGrossProfit() {
    RCProjectMoney _contractPrice = this.getContractPrice();
    RCProjectMoney _netPrice = this.getNetPrice();
    RCProjectMoney _substract = _contractPrice.substract(_netPrice);
    return _substract;
  }
  
  public Double getGrossProfitRate() {
    double _xifexpression = (double) 0;
    RCProjectMoney _contractPrice = this.getContractPrice();
    Double _amount = _contractPrice.getAmount();
    boolean _notEquals = ((_amount).doubleValue() != 0);
    if (_notEquals) {
      RCProjectMoney _grossProfit = this.getGrossProfit();
      Double _amount_1 = _grossProfit.getAmount();
      RCProjectMoney _contractPrice_1 = this.getContractPrice();
      Double _amount_2 = _contractPrice_1.getAmount();
      double _divide = DoubleExtensions.operator_divide(_amount_1, _amount_2);
      _xifexpression = _divide;
    } else {
      _xifexpression = 0;
    }
    return Double.valueOf(_xifexpression);
  }
  
  public RCProjectMoney getSalesExCost() {
    RCProjectMoney _xblockexpression = null;
    {
      Iterable<RCC3Budget> _filter = Iterables.<RCC3Budget>filter(this.budgets, RCC3Budget.class);
      RCC3Budget _head = IterableExtensions.<RCC3Budget>head(_filter);
      final RCProjectMoney engineerAdjust = _head==null?(RCProjectMoney)null:_head.calcAdjustNetPrice();
      final Function1<Void,RCProjectMoney> _function = new Function1<Void,RCProjectMoney>() {
          public RCProjectMoney apply(final Void it) {
            RCProjectMoney _zeroAmount = RCCostBreakDownImpl.this.project.getZeroAmount();
            return _zeroAmount;
          }
        };
      RCProjectMoney _withDefault = ObjectExtensions2.<RCProjectMoney>withDefault(engineerAdjust, _function);
      RCProjectMoney _totalEfc = this.project.getTotalEfc();
      RCProjectMoney _substract = _withDefault.substract(_totalEfc);
      _xblockexpression = (_substract);
    }
    return _xblockexpression;
  }
  
  public RCProjectMoney getSalesActualExCost() {
    RCProjectMoney _adjustTSC = this.getAdjustTSC();
    RCProjectMoney _totalRealEfc = this.project.getTotalRealEfc();
    RCProjectMoney _substract = _adjustTSC.substract(_totalRealEfc);
    return _substract;
  }
  
  public RCProjectMoney getAdjustTSC() {
    Iterable<RCC3Budget> _filter = Iterables.<RCC3Budget>filter(this.budgets, RCC3Budget.class);
    RCC3Budget _head = IterableExtensions.<RCC3Budget>head(_filter);
    RCProjectMoney _calcAdjustNetPrice = _head==null?(RCProjectMoney)null:_head.calcAdjustNetPrice();
    return _calcAdjustNetPrice;
  }
  
  public RCProjectMoney getSalesGrossProfit() {
    RCProjectMoney _grossProfit = this.getGrossProfit();
    RCProjectMoney _salesExCost = this.getSalesExCost();
    RCProjectMoney _plus = _grossProfit.plus(_salesExCost);
    return _plus;
  }
  
  public Double getSalesGrossProfitRate() {
    double _xifexpression = (double) 0;
    RCProjectMoney _contractPrice = this.getContractPrice();
    Double _amount = _contractPrice.getAmount();
    boolean _notEquals = ((_amount).doubleValue() != 0);
    if (_notEquals) {
      RCProjectMoney _salesGrossProfit = this.getSalesGrossProfit();
      Double _amount_1 = _salesGrossProfit.getAmount();
      RCProjectMoney _contractPrice_1 = this.getContractPrice();
      Double _amount_2 = _contractPrice_1.getAmount();
      double _divide = DoubleExtensions.operator_divide(_amount_1, _amount_2);
      _xifexpression = _divide;
    } else {
      _xifexpression = 0;
    }
    return Double.valueOf(_xifexpression);
  }
  
  public RCExchangeRate getExchangeRate() {
    RCExchangeRate _xblockexpression = null;
    {
      final RCProject p = this.getProject();
      Collection<RCExchangeRate> _exchangeRates = p.getExchangeRates();
      final Function1<RCExchangeRate,Boolean> _function = new Function1<RCExchangeRate,Boolean>() {
          public Boolean apply(final RCExchangeRate it) {
            CurrencyType _currencyType = p.getCurrencyType();
            CurrencyType _currencyType_1 = it.getCurrencyType();
            boolean _equals = Objects.equal(_currencyType, _currencyType_1);
            return Boolean.valueOf(_equals);
          }
        };
      RCExchangeRate _findFirst = IterableExtensions.<RCExchangeRate>findFirst(_exchangeRates, _function);
      _xblockexpression = (_findFirst);
    }
    return _xblockexpression;
  }
  
  public RCProjectMoney getZeroAmount() {
    RCProjectMoney _rCProjectMoney = new RCProjectMoney();
    final Procedure1<RCProjectMoney> _function = new Procedure1<RCProjectMoney>() {
        public void apply(final RCProjectMoney it) {
          it.setAmount(Double.valueOf(0d));
          RCExchangeRate _exchangeRate = RCCostBreakDownImpl.this.getExchangeRate();
          it.setExchange(_exchangeRate);
        }
      };
    RCProjectMoney _doubleArrow = ObjectExtensions.<RCProjectMoney>operator_doubleArrow(_rCProjectMoney, _function);
    return _doubleArrow;
  }
  
  public Double getTSCAmount() {
    Double _xblockexpression = null;
    {
      Iterable<RCC3Budget> _filter = Iterables.<RCC3Budget>filter(this.budgets, RCC3Budget.class);
      final RCC3Budget c3budget = IterableExtensions.<RCC3Budget>head(_filter);
      Double _xifexpression = null;
      RCC3BudgetType _type = c3budget.getType();
      boolean _equals = Objects.equal(_type, RCC3BudgetType.P3);
      if (_equals) {
        _xifexpression = null;
      } else {
        RCProjectMoney _netPrice = c3budget.getNetPrice();
        Double _hostAmount = _netPrice.toHostAmount();
        _xifexpression = _hostAmount;
      }
      _xblockexpression = (_xifexpression);
    }
    return _xblockexpression;
  }
  
  public void diagnose(final IDiagnoseAcceptor acceptor) {
    final Procedure1<RCBudget> _function = new Procedure1<RCBudget>() {
        public void apply(final RCBudget it) {
          it.diagnose(acceptor);
        }
      };
    IterableExtensions.<RCBudget>forEach(this.budgets, _function);
  }
  
  public static RCCostBreakDown create(final IObjectFactory objectFactory) {
    com.shrct.businessprocess.budget.RCCostBreakDown rCCostBreakDown = new com.shrct.businessprocess.budget.impl.RCCostBreakDownImpl(
    );
    objectFactory.create(rCCostBreakDown);
    return rCCostBreakDown;			
    
  }
  
  public static RCCostBreakDown createRCCostBreakDownImpl(final IObjectFactory objectFactory, final Procedure1<RCCostBreakDown> init) {
    com.shrct.businessprocess.budget.RCCostBreakDown rCCostBreakDown = new com.shrct.businessprocess.budget.impl.RCCostBreakDownImpl(
    );
    objectFactory.create(rCCostBreakDown);
    init.apply(rCCostBreakDown);
    
    return rCCostBreakDown;			
    
  }
  
  public RCCostBreakDownProxy toProxy() {
    com.shrct.businessprocess.budget.proxy.RCCostBreakDownProxy proxy = new com.shrct.businessprocess.budget.proxy.RCCostBreakDownProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    return proxy;
    
  }
}
